﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.Globalization;
using System.Text.RegularExpressions;
using Silverlight.ControlToolkit.Validator;

namespace Silverlight.ControlToolkit.Converters
{

    public enum DataTypes
    {
        None, //- The default datatype
        AlphabetsOnly, //Only Alphabets and Numbers
        AlphaNumeric, //Only Alphabets and Numbers
        Numeric, //Only natural numbers .. Leading zeros will be truncated (Int64)
        Currency, //$ with , and .00 is implied
        Digit, //Only whole Numbers .. Leading zeros will be shown (String) 
        DecimalOnly, //Numbers with decimal places
        Percent, //length is the number of positions: xxx.yyy% would be length 7
        PercentAuto,  //The value passed is automically multiplied by 100 before displaying and divided by 100 before reading
        DateOnly, //length = 10, format is xx/xx/xxxx
        DateTime, //length = 17, format is xx/xx/xxxx hh:mm am
        Phone, //length = 7, format is xxx-xxxx
        PhoneWithArea, //length = 10, format is (xxx) xxx-xxxx
        Zip, //length is variable based on DATA
        SSN, //length = 9, format is xxx-xx-xxxx
        TaxId, //For Business Tax ID. Format is 99-9999999, length=9
        Custom,
        RestrictedCharacters, //Lets the user enter only the range of characters specified
        Email
    }

    public enum Countries
    {
        CultureAtRuntime,
        USA,
        Canda
    }

    public class CustomFormatProvider : IFormatProvider, ICustomFormatter   
    {

        public const string CUSTOM_FORMAT_INDICATOR = "F:";
        public const string CUSTOM_UNFORMAT_INDICATOR = "U:";
        private static bool USE_LOCAL_PC_REGIONAL_SETTINGS = false;

        //Custom Formats :
        //# - Digit placeholder .If nothing then replaced by empty string - ""
        //Z - Digit placeholder .If nothing then replaced by zero - 0
        //@ - Alphanumeric `
        //! - Alphabets only [A-Z] placeholder
        public const char MASK_DIGIT = '#';
        public const char MASK_ZERO = 'Z';
        public const string MASK_ZERO_STRING = "Z";
        public const char MASK_ALPHA_NUMERIC = '@';
        public const char MASK_ALPHABETS = '!';

        public readonly static string SPECIAL_CHARS = string.Concat(MASK_DIGIT, MASK_ZERO, MASK_ALPHA_NUMERIC,MASK_ALPHABETS);

        public static DateTime MIN_DATE = new DateTime(1753, 1, 1);
        public static DateTime MAX_DATE = new DateTime(9999, 12, 31);

        public const string MIN_DATE_STRING = "?/?/?";
        public const string MAX_DATE_STRING = "*/*/*";
        public const string MIN_DATE_TIME_STRING = "?/?/? ?:? ?";
        public const string MAX_DATE_TIME_STRING = "*/*/* *:* *";

        #region ICustomFormatter Members

        public string Format(string theFormat, object arg, System.IFormatProvider formatProvider)
        {

            if (theFormat == null)
            {
                return string.Format("{0}", arg);
            }

            string strArg = null;

            //If the format passed is our custom format (All Custom format starts with the letter 'F:')
            if (theFormat.StartsWith(CUSTOM_FORMAT_INDICATOR))
            {

                //If the format is US Zip(#####-####) and if Text is exactly 5 characters then hyphen is not required
                //If theFormat.Equals(CUSTOM_FORMAT_INDICATOR & New String(MASK_DIGIT, 5) & "-" & New String(MASK_DIGIT, 4)) AndAlso _
                //    arg.ToString().Trim.Length = 5 Then
                //    theFormat = theFormat.Trim("-"c)
                //End If
                return this.GetFormattedString(arg.ToString().Trim(), theFormat);
            }

            //TO UnFormat
            else if (theFormat.StartsWith(CUSTOM_UNFORMAT_INDICATOR))
            {

                return this.GetUnFormattedString(arg.ToString().Trim(), theFormat);
            }

            //Standard Formats supported by .NET
            else
            {

                // If the object to be formatted supports the IFormattable
                // interface, pass the format specifier to the 
                // objects ToString method for formatting.


                //If TypeOf arg Is IFormattable Then

                //    Return CType(arg, IFormattable).ToString(theFormat, formatProvider)
                //    ' If the object does not support IFormattable, 
                //    ' call the objects ToString method with no additional
                //    ' formatting. 
                if (((arg != null)))
                {

                    strArg = arg.ToString();

                    //String Type is NOT formattable .. Hence convert the arg object to the correct datatype
                    DataTypes DisplayType = GetDisplayType(theFormat);
                    switch (DisplayType)
                    {
                        case DataTypes.Currency:
                        case DataTypes.DecimalOnly:
                        case DataTypes.Percent:
                        case DataTypes.PercentAuto:
                            if (Utilities.IsNumeric(strArg))
                            {

                                double dblRoundedValue = 0;

                                double.TryParse(strArg, NumberStyles.Any, null, out dblRoundedValue);

                                Int32 intDigits = default(Int32);

                                //Check if any extra formatting string passed is precision
                                if (theFormat.Trim().Length > 1 && Utilities.IsNumeric(theFormat.Substring(1)))
                                {
                                    //Get the precision desired
                                    intDigits = Convert.ToInt32(theFormat.Substring(1).Trim());

                                    //If type is percentage auto add 2 to scale as values are always
                                    //passed in minimum 2 decimal places by default 
                                    //For eg: for 7.25% the value passed will be 0.0725
                                    if (DisplayType == DataTypes.PercentAuto)
                                    {
                                        intDigits = intDigits + 2;
                                    }

                                    //Round the value using Math.Round cuss String.Format rounding algorithm 
                                    //is not as accurate as Math.Round
                                    dblRoundedValue = Math.Round(dblRoundedValue, intDigits);
                                }

                                if (DisplayType == DataTypes.Percent)
                                {
                                    return dblRoundedValue.ToString("n" + intDigits.ToString().Trim(), formatProvider) + " %";
                                }
                                else if (DisplayType == DataTypes.PercentAuto)
                                {
                                    return (dblRoundedValue * 100).ToString("n" + (intDigits - 2).ToString().Trim(), formatProvider) + " %";
                                }
                                else
                                {
                                    return dblRoundedValue.ToString(theFormat, formatProvider);
                                }
                            }



                            break;

                        case DataTypes.Numeric:

                        case DataTypes.DateOnly:
                            if (Utilities.IsDate(strArg))
                            {
                                DateTime tempValue = Convert.ToDateTime(strArg.Replace("11:59:59 PM", ""));

                                if (tempValue == DateTime.MinValue || tempValue == MIN_DATE)
                                    return MIN_DATE_STRING;
                                else if (tempValue == DateTime.MaxValue || tempValue == MAX_DATE)
                                    return MAX_DATE_STRING;
                                else
                                    return Convert.ToDateTime(strArg).ToString(theFormat, formatProvider);

                            }

                            break;

                        case DataTypes.DateTime:
                            if (Utilities.IsDate(strArg))
                            {
                                DateTime tempValue = Convert.ToDateTime(strArg);

                                if (tempValue == DateTime.MinValue || tempValue == MIN_DATE)
                                    return MIN_DATE_TIME_STRING;
                                else if (tempValue == DateTime.MaxValue || tempValue == MAX_DATE)
                                    return MAX_DATE_TIME_STRING;
                                else
                                    return Convert.ToDateTime(strArg).ToString(theFormat, formatProvider);
                            }

                            break;

                    }

                    return arg.ToString();
                }

                else
                {
                    return string.Empty;
                }
            }


        }

        #endregion

        #region IFormatProvider Members

        public object GetFormat(Type formatType)
        {
            if (object.ReferenceEquals(formatType, typeof(ICustomFormatter))) 
            {
                return this;
            }
            else 
            {
                return null;
            }
        }

        #endregion



        private string GetFormattedString(string valueToFormat, string theFormat)
        {
        
            if (valueToFormat.Length == 0) {
                return string.Empty;
            }
            
            //Chop off the string "F:" from the Format
            theFormat = theFormat.Trim(CUSTOM_FORMAT_INDICATOR.ToCharArray());
            
            
            Int32 intExpectedArgLength = default(Int32);
            Int32 intTotLeftZeros = default(Int32);
            bool blnTotLeftZerosFound = false;
            
            foreach (char currentChar in theFormat.ToCharArray()) 
            {
                //The current char is a special one
                if (SPECIAL_CHARS.IndexOf(currentChar) >= 0) {
                    if (!blnTotLeftZerosFound && !currentChar.Equals(MASK_ZERO)) {
                        intTotLeftZeros = intExpectedArgLength;
                        blnTotLeftZerosFound = true;
                    }
                    intExpectedArgLength += 1;
                }
            }
            
            if (!blnTotLeftZerosFound) {
                intTotLeftZeros = intExpectedArgLength;
                blnTotLeftZerosFound = true;
            }
            
            System.Text.StringBuilder stbFormattedValue = new System.Text.StringBuilder(valueToFormat);
            
            //Pad zeros to the left of the string
            if (intTotLeftZeros > 0 && stbFormattedValue.Length < intExpectedArgLength) 
            {
                if (intTotLeftZeros >= (intExpectedArgLength - stbFormattedValue.Length)) 
                {
                    stbFormattedValue.Insert(0, "0", intExpectedArgLength - stbFormattedValue.Length);
                }
                else 
                {
                    stbFormattedValue.Insert(0, "0", intTotLeftZeros);
                }
            }
            
            Int32 intIndex = default(Int32);
            foreach (char currentChar in theFormat.ToCharArray()) 
            {
                
                //The current char is NOT a special one
                if (SPECIAL_CHARS.IndexOf(currentChar) < 0) 
                {
                    
                    if (intIndex < stbFormattedValue.Length) 
                    {
                        if (!Convert.ToChar(stbFormattedValue.ToString(intIndex, 1)).Equals(currentChar)) 
                        {
                            stbFormattedValue.Insert(intIndex, currentChar.ToString());
                        }
                    }
                    else if (intIndex == stbFormattedValue.Length) {
                        stbFormattedValue.Append(currentChar);
                    }
                    else {
                        break; // TODO: might not be correct. Was : Exit For
                    }
                }
                
                else if (currentChar.Equals(MASK_ZERO) && intIndex == stbFormattedValue.Length) {
                    stbFormattedValue.Append("0");
                }
                
                else {
                    
                    do {
                        if (intIndex < stbFormattedValue.Length && theFormat.IndexOf(stbFormattedValue.ToString(intIndex, 1)) >= 0 && SPECIAL_CHARS.IndexOf(stbFormattedValue.ToString(intIndex, 1)) < 0) {
                            
                            stbFormattedValue.Remove(intIndex, 1);
                        }
                        
                        else {
                            break; // TODO: might not be correct. Was : Exit Do
                        }
                    }
                    while (true);
                    
                }
                
                
                intIndex += 1;
            }
            
            //Special hard-coding for Zip code .. If - exists at the end take it off
            if (stbFormattedValue.ToString().Trim().EndsWith("-")) {
                if ((CUSTOM_FORMAT_INDICATOR + theFormat).Equals(GetDisplayFormat(DataTypes.Zip, Countries.USA))) {
                    stbFormattedValue.Remove(stbFormattedValue.Length - 1, 1);
                }
            }
            
            return stbFormattedValue.ToString();
        
        }

        private string GetUnFormattedString(string valueToUnFormat, string theFormat)
        {

            if (valueToUnFormat.Length == 0)
            {
                return string.Empty;
            }

            //Chop off the string "U:" from the Format
            theFormat = theFormat.Trim(CUSTOM_UNFORMAT_INDICATOR.ToCharArray());

            DataTypes DisplayType = GetDisplayType(theFormat);

            switch (DisplayType)
            {

                case DataTypes.Currency:
                case DataTypes.Percent:
                case DataTypes.PercentAuto:
                case DataTypes.Numeric:
                case DataTypes.DecimalOnly:

                    double dblVal = 0;
                    if (DisplayType == DataTypes.Currency)
                    {
                        double.TryParse(valueToUnFormat, NumberStyles.Currency, null, out dblVal);
                    }
                    else if (DisplayType == DataTypes.Percent)
                    {
                        double.TryParse(valueToUnFormat.Trim("%".ToCharArray()).Trim(), NumberStyles.Number, null, out dblVal);
                    }
                    else if (DisplayType == DataTypes.PercentAuto)
                    {
                        double.TryParse(valueToUnFormat.Trim("%".ToCharArray()).Trim(), NumberStyles.Number, null, out dblVal);
                        dblVal = dblVal / 100;
                    }
                    //Numeric and decimal
                    else
                    {
                        double.TryParse(valueToUnFormat, NumberStyles.Number, null, out dblVal);
                    }


                    //Check if any extra formatting string passed is precision
                    Int32 intScale = 2;
                    //Default
                    if (theFormat.Trim().Length > 1 && Utilities.IsNumeric(theFormat.Substring(1)))
                    {
                        //Get the precision desired
                        intScale = Convert.ToInt32(theFormat.Substring(1).Trim());

                        //If type is percentage add 2 to scale as values are always
                        //passed in minimum 2 decimal places by default 
                        //For eg: for 7.25% the value passed will be 0.0725
                        if (DisplayType == DataTypes.PercentAuto)
                        {
                            intScale = intScale + 2;
                        }

                        //Round the value using Math.Round cuss String.Format rounding algorithm 
                        //is not as accurate as Math.Round
                        dblVal = Math.Round(dblVal, intScale);
                    }


                    return dblVal.ToString("F" + intScale.ToString().Trim());

                case DataTypes.DateOnly:
                case DataTypes.DateTime:
                case DataTypes.Digit:
                case DataTypes.None:

                    return valueToUnFormat;

                default:

                    //Chop off all the literal characters
                    foreach (char currentChar in theFormat.ToCharArray())
                    {
                        //The current char is NOT a special one
                        if (valueToUnFormat.IndexOf(currentChar) >= 0)
                        {
                            valueToUnFormat = valueToUnFormat.Replace(currentChar.ToString(), "");
                        }
                    }


                    return valueToUnFormat;
            }

        }


        public static string GetDisplayFormat(DataTypes DisplayType)
        {
            return GetDisplayFormat(DisplayType, 2, Countries.CultureAtRuntime);
        }

        public static string GetDisplayFormat(DataTypes DisplayType, Int16 decimalPlaces)
        {
            return GetDisplayFormat(DisplayType, decimalPlaces, Countries.CultureAtRuntime);
        }

        public static string GetDisplayFormat(DataTypes DisplayType, Countries country)
        {
            return GetDisplayFormat(DisplayType, 2, country);
        }

        public static string GetDisplayFormat(DataTypes DisplayType, Int16 decimalPlaces, Countries country)
        {

            string strDecimalPlaces = "";
            strDecimalPlaces = decimalPlaces.ToString();
            //If decimalPlaces <> 2 Then
            //    strDecimalPlaces = decimalPlaces.ToString
            //End If

            if (country == Countries.CultureAtRuntime)
            {
                country = GetCountryBasedOnCulture(Thread.CurrentThread.CurrentUICulture);
            }

            switch (DisplayType)
            {
                case DataTypes.Currency:
                    return "c" + strDecimalPlaces;

                case DataTypes.Percent:
                    return "p" + strDecimalPlaces;

                case DataTypes.PercentAuto:
                    return "a" + strDecimalPlaces;

                case DataTypes.DecimalOnly:
                    return "n" + strDecimalPlaces;

                case DataTypes.Numeric:
                    return "n0";

                case DataTypes.SSN:
                    if (country == Countries.USA)
                    {
                        return CUSTOM_FORMAT_INDICATOR + new string(MASK_DIGIT, 3) + "-" + new string(MASK_DIGIT, 2) + "-" + new string(MASK_DIGIT, 4);
                        // "###-##-####"
                    }
                    else
                    {
                        return CUSTOM_FORMAT_INDICATOR + new string(MASK_DIGIT, 3) + " " + new string(MASK_DIGIT, 2) + " " + new string(MASK_DIGIT, 4);
                        // "### ## ####"
                    }


                case DataTypes.Phone:
                    return CUSTOM_FORMAT_INDICATOR + new string(MASK_DIGIT, 3) + "-" + new string(MASK_DIGIT, 4);
                // "###-####"

                case DataTypes.PhoneWithArea:
                    return CUSTOM_FORMAT_INDICATOR + "(" + new string(MASK_DIGIT, 3) + ") " + new string(MASK_DIGIT, 3) + "-" + new string(MASK_DIGIT, 4);
                // "(###) ###-####"

                case DataTypes.Zip:
                    if (country == Countries.USA)
                    {
                        return CUSTOM_FORMAT_INDICATOR + new string(MASK_DIGIT, 5) + "-" + new string(MASK_DIGIT, 4);
                        // "#####-####"
                    }
                    else
                    {
                        return string.Format("{0}{1}{2}{1} {2}{1}{2}", CUSTOM_FORMAT_INDICATOR, MASK_ALPHABETS, MASK_DIGIT);
                        // "A#A #A#"
                    }

                case DataTypes.DateOnly:
                    if (USE_LOCAL_PC_REGIONAL_SETTINGS && Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern.StartsWith("d"))
                    {
                        return "dd/MM/yyyy";
                        //"MM/dd/yyyy"
                    }
                    else
                    {
                        return "MM/dd/yyyy";
                    }

                case DataTypes.DateTime:
                    if (USE_LOCAL_PC_REGIONAL_SETTINGS && Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern.StartsWith("d"))
                    {
                        return "dd/MM/yyyy hh:mm:ss tt";
                    }
                    else
                    {
                        return "MM/dd/yyyy hh:mm:ss tt";
                    }

                case DataTypes.TaxId:
                    return CUSTOM_FORMAT_INDICATOR + new string(MASK_DIGIT, 2) + "-" + new string(MASK_DIGIT, 7);
                // "##-#######"

                default:
                    return "";
            }

        }

        public static DataTypes GetDisplayType(string format)
        {

            if (format == null || format.Trim().Length == 0)
            {
                return DataTypes.None;
            }


            switch (format.Substring(0, 1))
            {
                case "c":
                    return DataTypes.Currency;

                case "p":
                    return DataTypes.Percent;

                case "a":
                    return DataTypes.PercentAuto;

                case "n":
                    if (format.Equals(GetDisplayFormat(DataTypes.Numeric)))
                    {
                        return DataTypes.Numeric;
                    }
                    else
                    {
                        return DataTypes.DecimalOnly;
                    }


                case "M":
                case "d":
                    if (format.Equals(GetDisplayFormat(DataTypes.DateOnly)))
                    {
                        return DataTypes.DateOnly;
                    }
                    else
                    {
                        return DataTypes.DateTime;
                    }

                case MASK_ZERO_STRING:
                    return DataTypes.Custom;

                default:
                    return DataTypes.Custom;
            }

        }

        public static Countries GetCountryBasedOnCulture(CultureInfo currentCulture)
        {

            if (currentCulture.Name.EndsWith("US"))
            {
                return Countries.USA;
            }
            else
            {
                return Countries.Canda;
            }

        }

        public static Regex GetRegEx(DataTypes DisplayType)
        {
            return GetRegEx(DisplayType, Countries.CultureAtRuntime);
        }

        public static Regex GetRegEx(DataTypes DisplayType, Countries country)
        {


            string strPattern = "";

            if (country == Countries.CultureAtRuntime)
            {
                country = GetCountryBasedOnCulture(Thread.CurrentThread.CurrentUICulture);
            }

            switch (DisplayType)
            {

                case DataTypes.Currency:
                    //strPattern = "^((-?\$?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?))|(\(\$?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)\)))$"
                    strPattern = "^((-?\\$?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,})?|0(\\.[0-9]{0,})?|(\\.[0-9]{1,})?))|(\\(\\$?([1-9]{1}[0-9]{0,}(\\,[0-9]{3})*(\\.[0-9]{0,})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,})?|0(\\.[0-9]{0,})?|(\\.[0-9]{1,})?)\\)))$";
                    break;

                case DataTypes.DecimalOnly:
                    //strPattern = "^(\d|-)?(\d|,)*\.?\d*$"
                    strPattern = "^((-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,})?|0(\\.[0-9]{0,})?|(\\.[0-9]{1,})?))|(\\(\\$?([1-9]{1}[0-9]{0,}(\\,[0-9]{3})*(\\.[0-9]{0,})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,})?|0(\\.[0-9]{0,})?|(\\.[0-9]{1,})?)\\)))$";
                    break;

                case DataTypes.Percent:
                case DataTypes.PercentAuto:
                    //strPattern = "^(\d|-)?(\d|,)*\.?\d*\s?\%?$"
                    strPattern = "^((-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,})?|0(\\.[0-9]{0,})?|(\\.[0-9]{1,})?))|(\\(\\$?([1-9]{1}[0-9]{0,}(\\,[0-9]{3})*(\\.[0-9]{0,})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,})?|0(\\.[0-9]{0,})?|(\\.[0-9]{1,})?)\\)))\\s?\\%?$";
                    break;

                case DataTypes.Numeric:
                    //strPattern = "^(\d?$|-?[1-9]\d*$)"
                    strPattern = "^((-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*|[1-9]{1}[0-9]{0,}|0|(\\.[0-9]{1,})?))|(\\(\\$?([1-9]{1}[0-9]{0,}(\\,[0-9]{3})*|[1-9]{1}[0-9]{0,}|0|(\\.[0-9]{1,})?)\\)))$";
                    break;

                case DataTypes.Digit:
                    strPattern = "^\\d*$";
                    break;

                case DataTypes.AlphabetsOnly:
                    strPattern = "^[A-Za-z]*$";
                    break;

                case DataTypes.AlphaNumeric:
                    strPattern = "^[A-Za-z0-9]*$";
                    break;

                case DataTypes.SSN:
                    if (country == Countries.USA)
                    {
                        strPattern = "^\\d{3}-\\d{2}-\\d{4}?$";
                        //"###-##-####"
                    }
                    else
                    {
                        strPattern = "^\\d{3}\\s\\d{2}\\s\\d{4}?$";
                        //"### ## ####"
                    }

                    break;

                case DataTypes.Phone:
                    strPattern = "^[1-9]\\d{2}-\\d{4}?$";
                    break;

                case DataTypes.PhoneWithArea:
                    strPattern = "^\\([1-9]\\d{2}\\)\\s[1-9]\\d{2}-\\d{4}?$";
                    break;

                case DataTypes.Zip:
                    if (country == Countries.USA)
                    {
                        strPattern = "^\\d{5}(-\\d{4})?$";
                    }
                    else
                    {
                        strPattern = "^([AaBbCcEeGgHhJjKkLlMmNnPpRrSsTtVvXxYy]\\d[A-Za-z]\\s\\d[A-Za-z]\\d)$";
                    }

                    break;

                case DataTypes.DateOnly:

                    if (USE_LOCAL_PC_REGIONAL_SETTINGS && Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern.StartsWith("d"))
                    {
                        strPattern = "(?n:^(?=\\d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|(16|[2468][048]|[3579][26])00))|0?[1-9]|1\\d|2[0-8])(?<sep>[/.-])(?<month>0?[1-9]|1[012])\\2(?<year>(1[6-9]|[2-9]\\d)\\d{2})(?:(?=\\x20\\d)\\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\\d){0,2}(?i:\\ [AP]M))|([01]\\d|2[0-3])(:[0-5]\\d){1,2})?$)";
                    }
                    else
                    {
                        strPattern = "(?n:^(?=\\d)((?<month>(0?[13578])|1[02]|(0?[469]|11)(?!.31)|0" + "?2(?(.29)(?=.29.((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][" + "26])|(16|[2468][048]|[3579][26])00))|(?!.3[01])))(?<sep>[-./" + "])(?<day>0?[1-9]|[12]\\d|3[01])\\k<sep>(?<year>(1[6-9]|[2-9]\\d" + ")\\d{2})(?(?=\\x20\\d)\\x20|$))?$)";
                    }


                    break;


                case DataTypes.DateTime:
                    if (USE_LOCAL_PC_REGIONAL_SETTINGS && Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern.StartsWith("d"))
                    {
                        strPattern = "(?n:^(?=\\d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(?(.0?2)(?=.{3,4}(1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|(16|[2468][048]|[3579][26])00))|0?[1-9]|1\\d|2[0-8])(?<sep>[/.-])(?<month>0?[1-9]|1[012])\\2(?<year>(1[6-9]|[2-9]\\d)\\d{2})(?:(?=\\x20\\d)\\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]\\d){0,2}(?i:\\ [AP]M))|([01]\\d|2[0-3])(:[0-5]\\d){1,2})?$)";
                    }
                    else
                    {
                        strPattern = "(?n:^(?=\\d)((?<month>(0?[13578])|1[02]|(0?[469]|11)(?!.31)|0" + "?2(?(.29)(?=.29.((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][" + "26])|(16|[2468][048]|[3579][26])00))|(?!.3[01])))(?<sep>[-./" + "])(?<day>0?[1-9]|[12]\\d|3[01])\\k<sep>(?<year>(1[6-9]|[2-9]\\d" + ")\\d{2})(?(?=\\x20\\d)\\x20|$))?(?<time>((0?[1-9]|1[012])(:[0-5]" + "\\d){0,2}(?i:\\x20[AP]M))|([01]\\d|2[0-3])(:[0-5]\\d){1,2})?$)";
                    }

                    break;

                case DataTypes.TaxId:
                    strPattern = "^\\d{2}-\\d{7}?$";
                    break;

                case DataTypes.Email:
                    strPattern = "^[A-Za-z0-9](([_\\.\\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\\.\\-]?[a-zA-Z0-9]+)*)\\.([A-Za-z]{2,})$";
                    break;

                default:
                    strPattern = "";
                    break;
            }

            if (strPattern.Length > 0)
            {
                return new Regex(strPattern);
            }
            else
            {
                return null;
            }

        }

        public static Type GetDataTypeOfDisplayType(DataTypes displayType)
        {

            switch (displayType)
            {

                case DataTypes.Numeric:
                    return typeof(Int64);

                case DataTypes.Currency:
                case DataTypes.Percent:
                case DataTypes.PercentAuto:
                    return typeof(double);

                case DataTypes.DecimalOnly:
                    return typeof(decimal);

                case DataTypes.DateOnly:
                    return typeof(System.DateTime);

                case DataTypes.DateTime:
                    return typeof(DateTime);

                default:
                    return typeof(string);

            }

        }

        public static void AssignValue(ref object variable, string unformattedText, DataTypes displayType)
        {

            if (unformattedText == null)
            {
                unformattedText = string.Empty;
            }

            switch (displayType)
            {
                case DataTypes.Numeric:
                case DataTypes.Currency:
                case DataTypes.DecimalOnly:
                case DataTypes.Percent:
                case DataTypes.PercentAuto:
                    if (!Utilities.IsNumeric(unformattedText))
                    {
                        unformattedText = "0";
                    }

                    variable = Convert.ChangeType(unformattedText, variable.GetType(), NumberFormatInfo.InvariantInfo);

                    break;

                case DataTypes.DateOnly:
                case DataTypes.DateTime:
                    if (!Utilities.IsDate(unformattedText))
                    {
                        if (unformattedText.Trim().Equals(MAX_DATE_STRING) || unformattedText.Trim().Equals(MAX_DATE_TIME_STRING))
                        {
                            unformattedText = DateTime.MaxValue.ToString();
                        }
                        else
                        {
                            unformattedText = MIN_DATE.ToString();
                        }
                    }

                    variable = Convert.ChangeType(unformattedText, variable.GetType(), DateTimeFormatInfo.InvariantInfo);

                    break;

                default:
                    variable = unformattedText;
                    break;

            }

        }

        public static object GetValue(string unformattedText, DataTypes displayType)
        {

            object variable = null;

            switch (displayType)
            {

                case DataTypes.Numeric:
                    variable = new Int64();
                    break;

                case DataTypes.Currency:
                case DataTypes.Percent:
                case DataTypes.PercentAuto:
                    variable = new double();
                    break;

                case DataTypes.DecimalOnly:
                    variable = new decimal();
                    break;

                case DataTypes.DateOnly:
                case DataTypes.DateTime:
                    variable = new DateTime();
                    break;

                default:
                    variable = "";
                    break;

            }

            AssignValue(ref variable, unformattedText, displayType);
            
            return variable;

        }

        public static string GetSystemDefaultText(DataTypes displayType)
        {

            switch (displayType)
            {
                case DataTypes.Numeric:
                case DataTypes.Currency:
                case DataTypes.DecimalOnly:
                case DataTypes.Percent:
                case DataTypes.PercentAuto:
                    return "0";
                case DataTypes.DateOnly:
                    return MIN_DATE_STRING;
                case DataTypes.DateTime:
                    return MIN_DATE_TIME_STRING;
                default:
                    return "";
            }

        }

        public static HorizontalAlignment GetHorizontalAlignment(DataTypes displayType)
        {

            switch (displayType)
            {
                case DataTypes.Numeric:
                case DataTypes.Currency:
                case DataTypes.Percent:
                case DataTypes.DecimalOnly:
                case DataTypes.Digit:
                case DataTypes.Zip:
                    return HorizontalAlignment.Right;

                default:
                    return HorizontalAlignment.Left;
            }

        }

        public static bool IsDataValid(string data, DataTypes displayType)
        {
            string errorMessage = "";
            return IsDataValid(data, displayType, null, ref errorMessage);
        }


        public static bool IsDataValid(string data, DataTypes displayType, ref string errorMessage)
        {
            return IsDataValid(data, displayType, null, ref errorMessage);
        }

        public static bool IsDataValid(string data, DataTypes displayType, string strDisplayName, ref string errorMessage)
        {

            errorMessage = "";

            if (data == null || data.Length == 0)
            {
                return true;
            }

            Regex objRegExp = GetRegEx(displayType);
            string displayFormat = GetDisplayFormat(displayType);

            return IsDataValid(data, displayType, objRegExp, displayFormat, strDisplayName, ref errorMessage);


        }

        public static bool IsDataValid(string data, DataTypes displayType, Regex objRegExp, string displayFormat, string strDisplayName, ref  string errorMessage)
        {

            errorMessage = "";

            if (data == null || data.Length == 0 || objRegExp == null)
            {
                return true;
            }


            //Pattern matched - Validation passed
            if ((objRegExp.IsMatch(data)))
            {
                return true;
            }

            //Validation failed
            else
            {

                if (displayType == DataTypes.DateOnly && (data.Equals(CustomFormatProvider.MIN_DATE_STRING) || data.Equals(CustomFormatProvider.MAX_DATE_STRING)))
                {

                    return true;
                }

                else if (displayType == DataTypes.DateTime && (data.Equals(CustomFormatProvider.MIN_DATE_TIME_STRING) || data.Equals(CustomFormatProvider.MAX_DATE_TIME_STRING)))
                {

                    return true;
                }



                //Data is INVALID
                if (strDisplayName != null && strDisplayName.Length > 0)
                {
                    if ((displayFormat != null) && displayFormat.Trim().Length > 0)
                    {
                        errorMessage = string.Format(Resources.CustomFormatProvider_InValidDataWithDisplayNameWithDisplayFormat, strDisplayName, displayFormat);
                    }
                    else
                    {
                        errorMessage = string.Format(Resources.CustomFormatProvider_InValidDataWithDisplayName, strDisplayName);
                    }
                }

                else
                {

                    if ((displayFormat != null) && displayFormat.Trim().Length > 0)
                    {
                        errorMessage = string.Format(Resources.CustomFormatProvider_InValidDataWithDisplayFormat, displayFormat);
                    }
                    else
                    {
                        errorMessage = Resources.CustomFormatProvider_InValidData;
                    }
                }


                return false;
            }



        }
    }
}


